package fr.bugtracker.entity.technique;

import java.util.Collection;
import java.util.Date;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import javax.persistence.TableGenerator;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;
import javax.persistence.Version;

import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.hibernate.annotations.LazyToOne;
import org.hibernate.annotations.LazyToOneOption;
import org.hibernate.search.annotations.Indexed;
import org.hibernate.validator.constraints.Email;
import org.hibernate.validator.constraints.NotEmpty;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import fr.bugtracker.dao.technique.IdentifiableEntity;

/**
 * Classe entité utilisateur
 */
@Entity
@Indexed
@Table(name = "utilisateur")
@TableGenerator(name = "sequence_utilisateur", pkColumnValue = "seq_utilisateur", table = "sequence", pkColumnName = "seq_name", valueColumnName = "seq_count", allocationSize = 1)
public class Utilisateur implements UserDetails, IdentifiableEntity {

	/**
	 *
	 */
	private static final long serialVersionUID = -5986236903738781944L;

	/**
	 * identifiant technique
	 */
	@Id
	@Column(name = "id", unique = true)
	@GeneratedValue(strategy = GenerationType.TABLE, generator = "sequence_utilisateur")
	private Integer id;
	/**
	 * mot de passe
	 */
	@NotEmpty
	@Column(name = "password", length = 50, nullable = false, unique = true)
	private String password;
	/**
	 * login
	 */
	@NotEmpty
	@Email
	@Column(name = "username", length = 50, nullable = false)
	private String username;
	/**
	 * date de création
	 */
	@Temporal(TemporalType.TIMESTAMP)
	@Column(name = "date_creation", nullable = false)
	private Date dateCreation;
	/**
	 * date de suppression
	 */
	@Temporal(TemporalType.TIMESTAMP)
	@Column(name = "date_suppression")
	private Date dateSuppression;
	/**
	 * vrai si le compte n'est pas bloqué
	 */
	@Column(name = "account_non_locked", nullable = false)
	private boolean accountNonLocked;
	/**
	 * vrai si le compte n'est pas expiré
	 */
	@Column(name = "account_non_expired", nullable = false)
	private boolean accountNonExpired;
	/**
	 * vrai si le mot de passe n'est pas expiré
	 */
	@Column(name = "credentials_non_expired", nullable = false)
	private boolean credentialsNonExpired;
	/**
	 * vrai si l'utilisateur est actif
	 */
	@Column(name = "enabled", nullable = false)
	private boolean enabled;
	/**
	 * vrai si l'utilisateur est en attente de validation après une création de compte
	 */
	@Column(name = "en_attente_validation", nullable = false)
	private boolean enAttenteValidation;
	/**
	 * profil de l'utilisateur
	 */
	@LazyToOne(LazyToOneOption.PROXY)
	@ManyToOne
    @JoinColumn(name="ref_profil", nullable=false)
	private Profil profil;
	/**
	 * les informations du compte associé à l'utilisateur
	 */
	@LazyToOne(LazyToOneOption.PROXY)
	@OneToOne(cascade = CascadeType.PERSIST, optional = false)
	@JoinColumn(name = "ref_compte", nullable = false)
	private Compte compte;
	/**
	 * les informations sur l'utilisateur
	 */
	@LazyToOne(LazyToOneOption.PROXY)
	@OneToOne(cascade = CascadeType.PERSIST, optional = false)
	@JoinColumn(name = "ref_information", nullable = false)
	private Information information;
	/**
	 * version de l'utilisateur
	 */
	@Version
	private int version;

	/**
	 * Constructeur de la classe <code>Utilisateur</code>.
	 */
	public Utilisateur() {
		accountNonExpired = true;
		credentialsNonExpired = true;
		accountNonLocked = true;
		enabled = false;
		enAttenteValidation = true;
		compte = new Compte();
		information = new Information();
	}

	/**
	 * @see fr.bugtracker.dao.technique.IdentifiableEntity#getId()
	 */
	@Override
	public Integer getId() {
		return id;
	}

	/**
	 * <p><b>Accès en écriture à l'attribut id.</b></p>
	 * @param pId L'attribut id à modifier.
	 */
	public void setId(Integer pId) {
		id = pId;
	}

	/**
	 * @see org.springframework.security.core.userdetails.UserDetails#getPassword()
	 */
	@Override
	public String getPassword() {
		return password;
	}

	/**
	 * <p><b>Accès en écriture à l'attribut password.</b></p>
	 * @param pPassword L'attribut password à modifier.
	 */
	public void setPassword(String pPassword) {
		password = pPassword;
	}

	/**
	 * @see org.springframework.security.core.userdetails.UserDetails#getUsername()
	 */
	@Override
	public String getUsername() {
		return username;
	}

	/**
	 * <p><b>Accès en écriture à l'attribut username.</b></p>
	 * @param pUsername L'attribut username à modifier.
	 */
	public void setUsername(String pUsername) {
		username = pUsername;
	}

	/**
	 * <p><b>Accès en lecture à l'attribut dateCreation.</b></p>
	 * @return Retourne l'attribut dateCreation sous forme de <code>Date</code>.
	 */
	public Date getDateCreation() {
		return dateCreation;
	}

	/**
	 * <p><b>Accès en écriture à l'attribut dateCreation.</b></p>
	 * @param pDateCreation L'attribut dateCreation à modifier.
	 */
	public void setDateCreation(Date pDateCreation) {
		dateCreation = pDateCreation;
	}

	/**
	 * <p><b>Accès en lecture à l'attribut dateSuppression.</b></p>
	 * @return Retourne l'attribut dateSuppression sous forme de <code>Date</code>.
	 */
	public Date getDateSuppression() {
		return this.dateSuppression;
	}

	/**
	 * <p><b>Accès en écriture à l'attribut dateSuppression.</b></p>
	 * @param dateSuppression L'attribut dateSuppression à modifier.
	 */
	public void setDateSuppression(Date dateSuppression) {
		this.dateSuppression = dateSuppression;
	}

	/**
	 * <p><b>Accès en lecture à l'attribut enAttenteValidation.</b></p>
	 * @return Retourne l'attribut enAttenteValidation sous forme de <code>boolean</code>.
	 */
	public boolean isEnAttenteValidation() {
		return enAttenteValidation;
	}

	/**
	 * <p><b>Accès en écriture à l'attribut enAttenteValidation.</b></p>
	 * @param pEnAttenteValidation L'attribut enAttenteValidation à modifier.
	 */
	public void setEnAttenteValidation(boolean pEnAttenteValidation) {
		enAttenteValidation = pEnAttenteValidation;
	}

	/**
	 * <p><b>Accès en lecture à l'attribut profil.</b></p>
	 * @return Retourne l'attribut profil sous forme de <code>Profil</code>.
	 */
	public Profil getProfil() {
		return this.profil;
	}

	/**
	 * <p><b>Accès en écriture à l'attribut profil.</b></p>
	 * @param profil L'attribut profil à modifier.
	 */
	public void setProfil(Profil profil) {
		this.profil = profil;
	}

	/**
	 * @see org.springframework.security.core.userdetails.UserDetails#getAuthorities()
	 */
	@Override
	@Transient
	public Collection<? extends GrantedAuthority> getAuthorities() {
		return profil.getListeRole();
	}

	/**
	 * @see org.springframework.security.core.userdetails.UserDetails#isAccountNonExpired()
	 */
	@Override
	@Transient
	public boolean isAccountNonExpired() {
		return accountNonExpired;
	}

	/**
	 * @see org.springframework.security.core.userdetails.UserDetails#isAccountNonLocked()
	 */
	@Override
	@Transient
	public boolean isAccountNonLocked() {
		return accountNonLocked;
	}

	/**
	 * @see org.springframework.security.core.userdetails.UserDetails#isCredentialsNonExpired()
	 */
	@Override
	@Transient
	public boolean isCredentialsNonExpired() {
		return credentialsNonExpired;
	}

	/**
	 * @see org.springframework.security.core.userdetails.UserDetails#isEnabled()
	 */
	@Override
	@Transient
	public boolean isEnabled() {
		return enabled;
	}

	/**
	 * <p><b>Accès en écriture à l'attribut accountNonLocked.</b></p>
	 * @param pAccountNonLocked L'attribut accountNonLocked à modifier.
	 */
	public void setAccountNonLocked(boolean pAccountNonLocked) {
		accountNonLocked = pAccountNonLocked;
	}

	/**
	 * <p><b>Accès en écriture à l'attribut accountNonExpired.</b></p>
	 * @param pAccountNonExpired L'attribut accountNonExpired à modifier.
	 */
	public void setAccountNonExpired(boolean pAccountNonExpired) {
		accountNonExpired = pAccountNonExpired;
	}

	/**
	 * <p><b>Accès en écriture à l'attribut credentialsNonExpired.</b></p>
	 * @param pCredentialsNonExpired L'attribut credentialsNonExpired à modifier.
	 */
	public void setCredentialsNonExpired(boolean pCredentialsNonExpired) {
		credentialsNonExpired = pCredentialsNonExpired;
	}

	/**
	 * <p><b>Accès en écriture à l'attribut enabled.</b></p>
	 * @param pEnabled L'attribut enabled à modifier.
	 */
	public void setEnabled(boolean pEnabled) {
		enabled = pEnabled;
	}

	/**
	 * <p><b>Accès en lecture à l'attribut version.</b></p>
	 * @return Retourne l'attribut version sous forme de <code>int</code>.
	 */
	public int getVersion() {
		return version;
	}

	/**
	 * <p><b>Accès en écriture à l'attribut version.</b></p>
	 * @param pVersion L'attribut version à modifier.
	 */
	public void setVersion(int pVersion) {
		version = pVersion;
	}

	/**
	 * <p><b>Accès en lecture à l'attribut compte.</b></p>
	 * @return Retourne l'attribut compte sous forme de <code>Compte</code>.
	 */
	public Compte getCompte() {
		return compte;
	}

	/**
	 * <p><b>Accès en écriture à l'attribut compte.</b></p>
	 * @param pCompte L'attribut compte à modifier.
	 */
	public void setCompte(Compte pCompte) {
		compte = pCompte;
	}

	/**
	 * <p><b>Accès en lecture à l'attribut information.</b></p>
	 * @return Retourne l'attribut information sous forme de <code>Information</code>.
	 */
	public Information getInformation() {
		return information;
	}

	/**
	 * <p><b>Accès en écriture à l'attribut information.</b></p>
	 * @param pInformation L'attribut information à modifier.
	 */
	public void setInformation(Information pInformation) {
		information = pInformation;
	}

	/**
	 * @see java.lang.Object#equals(java.lang.Object)
	 */
	@Override
	public boolean equals(Object obj) {
		if (this == obj) {
			return true;
		}
		if (obj == null) {
			return false;
		}
		if (!(obj instanceof Utilisateur)) {
			return false;
		}
		Utilisateur other = (Utilisateur) obj;
		return new EqualsBuilder().append(id, other.id).isEquals();
	}

	/**
	 * @see java.lang.Object#hashCode()
	 */
	@Override
	public int hashCode() {
		return new HashCodeBuilder(17, 37).append(id).toHashCode();
	}

	/**
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		ToStringBuilder builder = new ToStringBuilder(this);
		builder.append("id", this.id);
		builder.append("password", this.password);
		builder.append("username", this.username);
		builder.append("dateCreation", this.dateCreation);
		builder.append("dateSuppression", this.dateSuppression);
		builder.append("accountNonLocked", this.accountNonLocked);
		builder.append("accountNonExpired", this.accountNonExpired);
		builder.append("credentialsNonExpired", this.credentialsNonExpired);
		builder.append("enabled", this.enabled);
		builder.append("enAttenteValidation", this.enAttenteValidation);
		builder.append("profil", this.profil);
		builder.append("compte", this.compte);
		builder.append("information", this.information);
		builder.append("version", this.version);
		return builder.toString();
	}

}